package com.by.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.SpringVersion;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.EnumSet;
import java.util.List;

/**
 * @author LittleDesire
 * @description
 * @date 2022-03-22 周二 20:30
 * @since 17
 */
@Configuration
@EnableWebMvc
@RestController
@ComponentScan("com.by.controller")
public class WebInit implements WebApplicationInitializer, WebMvcConfigurer {

    /**
     * 启动注册
     *
     * @param servletContext 服务容器
     */
    @Override
    public void onStartup(ServletContext servletContext) {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(this.getClass());
        ctx.setServletContext(servletContext);
        // 服务调度器
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        dispatcher.addMapping("/");
        dispatcher.setLoadOnStartup(1);
        // 字符编码过滤器
        CharacterEncodingFilter cef = new CharacterEncodingFilter("UTF-8");
        FilterRegistration.Dynamic frd = servletContext.addFilter("cef", cef);
        // 解决PrintWriter out 输出乱码
        frd.setInitParameter("forceEncoding", "true");
        frd.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), true, "/*");
    }

    /**
     * 静态资源处理器
     *
     * @param registry 注册
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**/*.html").addResourceLocations("/");
        registry.addResourceHandler("/img/**").addResourceLocations("/img/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/**/*.*").addResourceLocations("/static/");
    }

    /**
     * 消息转换器
     *
     * @param converters 转换器
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        StringHttpMessageConverter shmc = new StringHttpMessageConverter();
        shmc.setDefaultCharset(StandardCharsets.UTF_8);
        List<MediaType> mediaTypes = List.of(MediaType.parseMediaType("text/html;charset=UTF-8"));
        shmc.setSupportedMediaTypes(mediaTypes);
        converters.add(shmc);

        //如下配置需要引入jackson组件，主要解决json输出，面向接口开发用的
        MappingJackson2HttpMessageConverter mjhmc = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        JavaTimeModule jtm = new JavaTimeModule();
        //LocalDateTime
        jtm.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        jtm.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        //LocalDate
        jtm.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        jtm.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        //LocalTime
        jtm.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        jtm.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        objectMapper.registerModule(jtm);
        //java.util.Date //设置日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(sdf);
        mjhmc.setObjectMapper(objectMapper);
        //设置中文编码格式
        mjhmc.setSupportedMediaTypes(List.of(MediaType.parseMediaType("application/json;charset=UTF-8")));
        converters.add(mjhmc);
    }

    /**
     * 跨域过滤器
     */
   /* @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 设置跨域路径
        registry.addMapping("/m")
                // 设置允许请求跨域的域名
                .allowedOrigins("*")
                // 是否允许证书
                .allowCredentials(true)
                // 设置允许的方法
                .allowedMethods("GET","POST","DELETE","PUT")
                // 设置允许的header属性
                .allowedHeaders("*")
                // 设置跨域允许时间
                .maxAge(3600);
    }*/
    @RequestMapping("/")
    public String index() {
        return String.format("Hello 爪哇 [%s]", SpringVersion.getVersion());
    }

    // 乱码
    @RequestMapping("p1")
    public void p1(PrintWriter out) {
        out.printf("p1 乱码 [%s]", SpringVersion.getVersion());
    }

    // 没有乱码
    @RequestMapping("/p2")
    public void p2(HttpServletResponse resp) throws IOException {
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.printf("p1 没有乱码 [%s]", SpringVersion.getVersion());
        out.flush();
        out.close();
    }

    // 默认请求/默认参数 get 不乱码，  传入参数 post 乱码
    @RequestMapping("/p3")
    public String p3(@RequestParam(name = "name", required = false, defaultValue = "刻晴") String name, HttpServletRequest req) {
        return String.format("名字：%s。方法：%s", name, req.getMethod());
    }
}
